﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;

namespace PlusPlusPaint.Layers
{
    class VisualObjectLayer : BasicLayer
    {
        #region member variables
        VisualObjects.IVisualObject contained;
        #endregion

        #region properties
        public bool AcceptsMostText
        {
            get
            {
                if (contained == null)
                    return false;
                return contained.AcceptsMostText;
            }
        }
        public override Point Location
        {
            get
            {
                if (contained != null)
                    return contained.Location;
                return new Point(0, 0);
            }
        }

        public override Size Size
        {
            get
            {
                if (contained != null)
                    return contained.Size;
                return new Size(1, 1); // Necessary for image constructors to not blow up.
            }
        }

        public override Rectangle ClientRectangle
        {
            get
            {
                return new Rectangle(this.Location, this.Size);
            }
        }

        public override bool CanFreeDraw
        {
            get
            {
                return false;
            }
        }

        public override bool Explodable
        {
            get
            {
                return false;
            }
        }
        #endregion

        #region constructors
        public VisualObjectLayer()
        {
            this.Visible = true;
        }
        #endregion

        #region overrides
        public override bool PositionIsInHitbox(Point p)
        {
            if (contained == null)
                return false;
            return contained.PositionIsInHitbox(p);
        }

        public override void ApplyToolToPoint(Tools.ISketchTool t, Point p)
        {
            t.GiveAccessToLayer(this, p);
        }

        public override bool CanHaveToolApplied(Tools.ISketchTool t)
        {
            return true; // Visual Object Layers should manage any tool.
        }

        public override ILayer Clone()
        {
            VisualObjectLayer vol = new VisualObjectLayer();
            if (contained == null)
                return vol;
            vol.ReplaceContentsWith(contained.Clone());
            return vol;
        }

        public override void BurnOn(Image i)
        {
            if (contained == null)
                return;
            contained.BurnOn(i);
        }
        
        public override SerializedObject Serialize()
        {
            if (contained == null)
                return new SerializedObject("VisualObjectLayer");
            List<SerializedObject> l = new List<SerializedObject>();
            l.Add(this.contained.Serialize());
            Dictionary<string, string> namedStrings = new Dictionary<string, string>();
            namedStrings["name"] = Name;
            return new SerializedObject("VisualObjectLayer", unnamedSubobjects: l, namedStrings: namedStrings);
        }
        
        public override void Deserialize(SerializedObject s)
        {
            if (s.UnnamedSubobjects.Count == 0)
            {
                this.contained = null;
                return;
            }
            Name = s.NamedStrings["name"];
            this.DeserializeSubobject(s.UnnamedSubobjects.First());
        }
        #endregion

        #region public methods
        public void ReplaceContentsWith(VisualObjects.IVisualObject vo)
        {
            contained = vo;
        }

        // Sometimes, I have the feeling I'm still writing C++.
        public void Invoke<T>(Action<T> a) where T : class, VisualObjects.IVisualObject, new()
        {
            T t = contained as T;
            if (t == null)
                contained = t = new T();
            a(t);
        }
        #endregion

        #region private methods
        private void DeserializeSubobject(SerializedObject so)
        {
            switch (so.Name.ToLower())
            {
                case "filledellipse":
                    this.contained = new VisualObjects.FilledEllipse();
                    break;
                case "emptyellipse":
                    this.contained = new VisualObjects.EmptyEllipse();
                    break;
                case "filledrectangle":
                    this.contained = new VisualObjects.FilledRectangle();
                    break;
                case "emptyrectangle":
                    this.contained = new VisualObjects.EmptyRectangle();
                    break;
                case "linesegment":
                    this.contained = new VisualObjects.LineSegment();
                    break;
                case "textarea":
                    this.contained = new VisualObjects.TextArea();
                    break;
                case "linesegmentgroup":
                    this.contained = new VisualObjects.LineSegmentGroup();
                    break;
                default:
                    throw new Exception("Unrecognised Visual Object " + so.Name + ".");
            }
            this.contained.Deserialize(so);
        }
        #endregion
    }
}
